package com.only4play.filter;


import com.only4play.constant.SSOConstant;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author liyuncong
 * @version 1.0
 * @file FilterContainer
 * @brief 过滤器容器
 * @details 过滤器容器
 * @date 2023-11-19
 *
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                     NAME               DESCRIPTION
 * 2023-11-19               liyuncong          Created
 */
@Setter
public class FilterContainer extends ParamContainer implements Filter {

    protected String excludeUrls;
    private List<AbstractClientFilter> filters;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        if (CollectionUtils.isEmpty(filters)) {
            throw new IllegalAccessError("filters empty");
        }
        for (AbstractClientFilter filter : filters) {
            filter.setAppId(getAppId());
            filter.setAppSecret(getAppSecret());
            filter.setServerUrl(getServerUrl());
            filter.init(filterConfig);
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
        throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        if (isExcludeUrl(request.getServletPath())) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        for (AbstractClientFilter filter : filters) {
            if (filter.isAccessAllowed(request, response)) {
                return;
            }
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        if (CollectionUtils.isEmpty(filters)) {
            return;
        }
        filters.forEach(Filter::destroy);
    }

    private boolean isExcludeUrl(String url) {
        if (StringUtils.isBlank(excludeUrls)) {
            return false;
        }
        final Map<Boolean, List<String>> map = Arrays.stream(excludeUrls.split(","))
            .collect(Collectors.partitioningBy(u -> u.endsWith(SSOConstant.URL_FUZZY_MATCH)));
        List<String> urlList = map.get(false);
        if (urlList.contains(url)) {
            return true;
        }
        List<String> urls = map.get(false);
        for (String matchUrl : urls) {
            if (url.startsWith(matchUrl.replace(SSOConstant.URL_FUZZY_MATCH, ""))) {
                return true;
            }
        }
        return false;
    }
}
